#include <stdint.h>
#include <string.h>
#include "esp_log.h"
#include "reg.h"
#include "nvs_app.h"


static int rs485_baud_check(void *arg);
static int spp_name_check(void *arg);
static void rs485_baud_func(void *arg);
static void spp_name_func(void *arg);

/********************************************************************************/
uint16_t ver_deg = 0x0101;
uint16_t rs485_baud = 96;
char spp_name[16] = {'B','T','_','P','O','R','T','_','N','A','M','E','\0','\0','\0','\0'};
/********************************************************************************/
static uint16_t reg_hold[REG_HOLD_LEN] = {0};

const reg_map_t reg_map_head = {
    1, REG_HOLD_START_ADDR, REG_HOLD_LEN, reg_hold, NULL
};
/********************************************************************************/
const reg_obj reg_obj_list[] = {
    {REG_HOLD_START_ADDR, 1, REG_ONLY_READ, &ver_deg, NULL, NULL},
    {REG_HOLD_START_ADDR + 1, 1, REG_READ_WRITE, &rs485_baud, rs485_baud_check, rs485_baud_func},
    {REG_HOLD_START_ADDR + 2, 8, REG_READ_WRITE, &spp_name[0], spp_name_check, spp_name_func}
};
/********************************************************************************/
static int rs485_baud_check(void *arg)
{
    uint16_t baud = reg_hold_read(1);
    if((baud == 96) || (baud == 192) || (baud == 384) || (baud == 576) || (baud == 1152))
    {
        return 1;
    }
    else
    {
        return -1;
    }
}

static int spp_name_check(void *arg)
{
    uint16_t reg = reg_hold_read(9);
    char last_char = reg >>8;
    if(last_char == '\0')
    {
        return 1;
    }
    else
    {
        return -1;
    }
}

/*******************************************************************************/
static void rs485_baud_func(void *arg)
{
    nvs_write_send(NVS_BAUD);
}

static void spp_name_func(void *arg)
{
    nvs_write_send(NVS_SPP_NAME);
}
/********************************************************************************/

/**
 * @brief 读取寄存器数据
 * @param addr 寄存器地址
 * @return 寄存器数据
 */
uint16_t reg_hold_read(uint16_t addr)
{
    if (addr >= REG_HOLD_START_ADDR && addr <= REG_HOLD_END_ADDR) 
    {
        return reg_hold[addr - REG_HOLD_START_ADDR];
    }
    return 0;
}

/**
 * @brief 写入寄存器数据
 * @param addr 寄存器地址
 * @param data 写入数据
 * @return 写入是否成功
 */
uint16_t reg_hold_write(uint16_t addr, uint16_t data)
{
    if (addr >= REG_HOLD_START_ADDR && addr <= REG_HOLD_END_ADDR) {
        reg_hold[addr - REG_HOLD_START_ADDR] = data;
        return 1;
    }
    return 0;
}

/**
 * @brief 寄存器地址检查
 * @param addr 寄存器地址
 * @return 地址是否有效
 */
uint16_t reg_hold_addr_check(uint16_t addr)
{
    if (addr >= REG_HOLD_START_ADDR && addr <= REG_HOLD_END_ADDR) 
    {
        return 1;
    }
    return 0;
}

/**
 * @brief 初始化寄存器
 * @return 初始化是否成功
 */
uint16_t reg_hold_init(void)
{
    for (uint16_t i = 0; i < sizeof(reg_obj_list) / sizeof(reg_obj); i++) 
    {
        memcpy(reg_hold + reg_obj_list[i].addr - REG_HOLD_START_ADDR, 
        reg_obj_list[i].data, reg_obj_list[i].len * sizeof(uint16_t));
    }
    return 1;
}

/**
 * @brief 寄存器事件处理
 * @param addr 寄存器地址
 * @param len 寄存器长度
 */
void reg_hold_event(uint16_t addr, uint16_t len)
{
    uint16_t a = addr;
    uint16_t b = a + len - 1;
    ESP_LOGE("Hold", "reg_hold_event: %d, %d", a, b);
    for (uint16_t i = 0; i < sizeof(reg_obj_list) / sizeof(reg_obj); i++) 
    {
        reg_obj *obj = (reg_obj *)&reg_obj_list[i];
        uint16_t A = obj->addr;
        uint16_t B = A + obj->len - 1;
        if (a <= B && b >= A) 
        {
            if(obj->rw == REG_READ_WRITE)
            {
                ESP_LOGE("Hold", "reg_hold_event: %d, %d, %d", obj->addr, obj->len, obj->rw);
                if(obj->check)
                {
                    if(obj->check(NULL) == 1)
                    {
                        memcpy(obj->data, reg_hold + obj->addr - REG_HOLD_START_ADDR, obj->len * sizeof(uint16_t));
                        ESP_LOGE("Hold", "reg check pass: %d, %d, %d", obj->addr, obj->len, obj->rw);
                        if(obj->func)
                        {
                            ESP_LOGE("Hold", "reg func call: %d, %d, %d", obj->addr, obj->len, obj->rw);
                            obj->func(NULL);
                        }
                        else
                        {
                            ESP_LOGE("Hold", "reg func null: %d, %d, %d", obj->addr, obj->len, obj->rw);
                        }
                    }
                    else
                    {
                        ESP_LOGE("Hold", "reg check fail: %d, %d, %d", obj->addr, obj->len, obj->rw);
                        memcpy(reg_hold + obj->addr - REG_HOLD_START_ADDR,
                            obj->data, 
                            obj->len * sizeof(uint16_t));
                    }
                }
                else
                {
                    ESP_LOGE("Hold", "reg check null: %d, %d, %d", obj->addr, obj->len, obj->rw);
                    memcpy(reg_hold + obj->addr - REG_HOLD_START_ADDR,
                        obj->data, 
                        obj->len * sizeof(uint16_t));
                }
            }
            else
            {
                ESP_LOGE("Hold", "reg is only read: %d, %d, %d", obj->addr, obj->len, obj->rw);
                memcpy(reg_hold + obj->addr - REG_HOLD_START_ADDR,
                       obj->data, 
                       obj->len * sizeof(uint16_t));
            }
        }
    }
}

